// RequeustQueue.cs
//
//  Copyright (C) 2008 Whitemice Consulting
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//

using System;
using System.Threading;
using System.Collections.Generic;

namespace Whitemice.ZOGI.Backend
{
  public class RequestQueue
  { 
    List<QueuedCommand>                      queue;
    Dictionary<int,List<IZOGIFetchCommand>>  fetchQueue;
    
    public RequestQueue()
    {
      queue = new List<QueuedCommand>();
      fetchQueue = new Dictionary<int, List<IZOGIFetchCommand>>();
    } // end ctor
    
    public IZOGICommand Pop()
    {
      IZOGICommand command;
      
      lock(queue)
      {
        if (queue.Count > 0)
        {
          queue.Sort(delegate(QueuedCommand c1,QueuedCommand c2) 
          { 
            return 0; 
          });
          command = queue[0].Pop();
          queue.RemoveAt(0);
          
        } else command = null;  
      } // end lock
      return command;
    } // end Pop
    
    public void Push(IZOGICommand c, List<Entity> x)
    {
      Console.WriteLine("RequestQueue.Push");
      lock(queue)
      {
        queue.Add(new QueuedCommand(c, x));
        if (c is Whitemice.ZOGI.IZOGIFetchCommand)
        {
          IZOGIFetchCommand f;
          
          f = (c as Whitemice.ZOGI.IZOGIFetchCommand);
          lock(fetchQueue)
          {
            foreach(int objectId in f.ObjectIds)
              if (fetchQueue.ContainsKey(objectId))
              {
                fetchQueue[objectId].Add(f);
              } else 
                {
                  List<IZOGIFetchCommand> l;
                  
                  l = new List<IZOGIFetchCommand>();
                  l.Add(f);
                  fetchQueue.Add(objectId, l);
                }
          } // end lock-fetchQueue
        } // end if-is-fetchCommand
      } // end lock
    } // end Push
    
    public void ReceiveObject(Entity e)
    {
      lock(fetchQueue)
      {
        if (fetchQueue.ContainsKey(e.ObjectId))
        {
          List<IZOGIFetchCommand> list = fetchQueue[e.ObjectId];
          list.RemoveAll(delegate(IZOGIFetchCommand c)
          {
            if (!(c.Cache.Contains(e)))
              c.Cache.Add(e);
            if (c.IsSaited)
            {
              lock(queue)
              {
                queue.RemoveAll(delegate(QueuedCommand q)
                {
                  if (q.Command == c) return true;
                  return false;
                });
                ThreadPool.QueueUserWorkItem (new WaitCallback(FetchCallback), c);
              } // end lock-queue
              return true;
            } // end if-saited
            return false;
          }); // end list-remove-delegate
          if (list.Count == 0)
            fetchQueue.Remove(e.ObjectId);
          list = null;
        } // end if-entity-is-requested
      } // end lock
    } // end ReceiveObject
    
    protected virtual void FetchCallback(object p)
    {
      IZOGIFetchCommand c;
      
      c = (p as Whitemice.ZOGI.IZOGIFetchCommand);
      c.Callback(c.Cache, c.Context, null);
    }
  } // end class
}
